package lk.icta.core.service;

import lk.icta.core.dto.LandAssociationDetails;
import lk.icta.core.dto.LandDetails;
import lk.icta.core.entity.*;
import lk.icta.user.entity.User;
import org.hibernate.exception.DataException;

import java.util.Date;
import java.util.List;
import java.util.Map;

public interface LandManagementService {

    /**
     * Add an Un-Alienated land
     *
     * @param land Land to be added
     * @param user User requesting to add land
     */
    public void addInitialUnAlienatedLand(Land land, User user, String language);

    /**
     * Add an Alienated land
     *
     * @param land       Land to be added
     * @param alienation Alienation information
     * @param user       User requesting to ad land
     */
    public void addInitialAlienatedLand(Land land, Alienation alienation, User user, String language);

    /**
     * Add a detail Un-Alienated land
     *
     * @param land Land to be added
     * @param user User requesting to add the land
     */
    public void addDetailUnAlienatedLand(Land land, long alienationId, LandAssociation landAssociation, User user, String language);

    /**
     * Add a sub divided land
     *
     * @param land Land to be added
     * @param user User requesting to add the land
     */
    public void addSubDividedLand(Land land, User user, String language);

    /**
     * Edit a sub divided land
     *
     * @param land Land to be added
     * @param user User requesting to add the land
     */
    public void editSubDividedLand(Land land, User user, String language);

    /**
     * Update a detail Un-Alienated land
     *
     * @param land Land to be updated
     * @param user User requesting to update the land
     */
    public void updateDetailUnAlienatedLand(Land land, long alienationId, LandAssociation landAssociation, User user, String language);

    /**
     * Delete a detail Un-Alienated land
     *
     * @param land Land to be deleted
     * @param user User requesting to delete the land
     */
    public void deleteDetailUnAlienatedLand(Land land, User user);

    public void deleteDetailUnAlienatedLandFromDatabase(Land land, User user);

    /**
     * Add detail Alienated land
     *
     * @param land         Land to be added
     * @param alienationId Alienation to be added
     * @param user         User requesting to add alienated land
     */

    public void deleteDetailAlienatedLandFromDatabase(Land land, long alienationId, User user);

    public void deleteDetailAlienatedLand(Land land, Alienation alienation, User user);

    public void addDetailAlienatedLand(Land land, Alienation alienation, LandAssociation landAssociation, User user, String language);

    /**
     * Update detail Alienated land
     *
     * @param land       Land to be updated
     * @param alienation Alienation to be updated
     * @param user       User requesting to update alienated land
     */
    public void updateDetailAlienatedLand(Land land, Alienation alienation, LandAssociation landAssociation, User user, String language);

    /**
     * Update Geographic information of a detailed land
     *
     * @param land Land to be updated
     * @param user User requesting to update alienated land
     */
    public void updateGEOInfo(Land land, User user);

    /**
     * Delete detail Alienated land
     *
     * @param land       Land to be deleted
     * @param alienation Alienation to be deleted
     * @param user       User requesting to delete alienated land
     */

    /**
     * Update a land
     *
     * @param land The land to be updated
     * @param user The user requesting to update the land
     */
    public void updateLand(Land land, User user);

    /**
     * Complete filling initial land information. (Available for detail land information)
     *
     * @param land Land to be completed
     * @param user User requesting to complete filling information
     */
    public void completeInitLandInformation(Land land, User user);

    /**
     * Approve land information
     *
     * @param land Land to be approved
     * @param user The user approving the land information
     */
    public void approveLandInformation(Land land, String approvalComment, User user);

    /**
     * Reject land information
     *
     * @param land Land to be rejected
     * @param user The user rejecting the land information
     */
    public void rejectLandInformation(Land land, String approvalComment, User user);

    /**
     * Returns a land corresponding to the given land id
     *
     * @param idUKey Id of the land
     * @param user   User requesting to search the land
     * @return The land corresponding to the given id
     */
    public Land getLandByIdUKey(long idUKey, User user);

    public List<LandDetails> getInitialActiveLandsByDSDivision(int dsDivisionId, User user);

    public List<LandDetails> getAllLandsReport(int gnDivisionId, String searchBy, Land.AlienationState alienationState, int alienationMethodId, int geoTypeId, String language, int pageNo);

    /**
     * Find Initial land records of the given GN Division
     *
     * @param gnDivisionId Id of the GN Division
     * @param user         User who requests the list of lands.
     * @return List of initial land records of the given GN Division
     */
    public List<LandDetails> getInitialActiveLandsByGNDivision(int gnDivisionId, User user);

    /**
     * Find detailed land records of the given GN Division
     *
     * @param gnDivisionId Id of the GN Division
     * @param user         User who requests the list of lands.
     * @return List of detailed land records of the given GN Division
     */
    public List<Land> getDetailActiveLandsByGNDivision(int gnDivisionId, User user);

    public List<LandDetails> getDetailActiveLandDetailsByGNDivision(int gnDivisionId, User user);

    /**
     * Find Incomplete detailed land records of the given GN Division
     *
     * @param gnDivisionId Id of the GN Division
     * @param user         User who requests the list of lands.
     * @return List of detailed land records of the given GN Division
     */
    public List<LandDetails> getIncompleteDetailLandsByGNDivision(int gnDivisionId, User user);

    /**
     * Returns list of all lands which are PENDING for approval
     *
     * @param user User requesting to list lands
     * @return List of lands
     */
    public List<LandDetails> getAllActivePendingLands(User user);
    // public List<Land> getAllActivePendingLands(User user);

    /**
     * Returns list of lands within a given GNDivision which are not ARCHIVED and PENDING for approval
     *
     * @param gnDivisionId Id of the GNDivision
     * @param user         User requesting to list lands
     * @return List of lands
     */
    public List<LandDetails> getActivePendingLandsByGNDivision(int gnDivisionId, User user);

    public List<LandDetails> getRejectedLandsByGNDivision(int gnDivisionId, User user);

    public List<LandDetails> getSubDividedLandsTobeApproveByGNDivision(int gnDivisionId, User user);

    public List<LandDetails> getSubDividedLandsTobeEditByGNDivision(int gnDivisionId, User user);


    /**
     * Find all incomplete land records
     *
     * @param user User requesting to find incomplete land records
     * @return List of detailed land records
     */
    public List<LandDetails> getAllIncompleteDetailLands(User user);

    public List<LandDetails> getActivePendingLandsByDSDivision(User user);

    /**
     * Find all Active-Pending land records( approvalState =  Pending for approval and mode =  Detail )
     *
     * @param dsDivisionId dsDivisionId
     * @param user         User requesting to find incomplete land records
     * @return LandDetails records
     */
    public List<LandDetails> getActivePendingLandsByDSDivisionId(int dsDivisionId, User user);

    public List<LandDetails> getRejectedLandsByDSDivision(User user);

    public List<LandDetails> getSubDividedLandsTobeApproveByDSDivision(User user);

    public List<LandDetails> getSubDividedLandsTobeEditByDSDivision(User user);

    /**
     * Find DetailLandReport of the given GN Division
     *
     * @param gnDivisionId Id of the GN Division
     * @param user         User who requests the list of lands.
     * @return List of detailed land records of the given GN Division
     */
    public List<LandDetails> getDetailLandReportByGNDivision(int gnDivisionId, User user);

    /**
     * Return Land by id
     *
     * @param id the Land ID
     * @return the Land
     */
    public Land getLandById(long id);

    /**
     * Find a Land by its reference number
     *
     * @param referenceNumber Reference Number of the Land
     * @return Land searched by reference number
     */
    public Land getLandByRef(long referenceNumber);

    /**
     * Return a list of approved, UnAlienated lands by the GN Division
     *
     * @param gnDivisionId Id of the G.N. Division
     * @param user         User requesting to list lands
     * @return List of approved, UnAlienated lands in the given GN Division
     */
    public List<Land> getApprovedUnAlienatedLandsByGNDivision(int gnDivisionId, User user);

    /**
     * Return a list of approved, UnAlienated lands by id
     *
     * @param id Id of the G.N. Division
     * @return Land of approved, UnAlienated lands
     */
    public Land getApprovedUnAlienatedLandById(long id);

    /**
     * Return list of all approved, UnAlienated lands
     *
     * @return List of Approved, UnAlienated lands
     */
    public List<Land> getAllApprovedUnAlienatedLands(User user);

    /**
     * Archive land
     *
     * @param land Land to be archived
     * @param user User requesting to archive land
     */
    public void archiveLand(Land land, User user);

    /**
     * Return a list of approved lands by the GN Division
     *
     * @param gnDivisionId Id of the G.N. Division
     * @param user         User requesting to list lands
     * @return List of approved lands in the given GN Division
     */
    public List<LandDetails> getApprovedLandsByGNDivision(int gnDivisionId, User user);

    public List<LandDetails> getLandAssociationsToBeApproved(int gnDivisionId, User user);

    public List<Land> getAllLandAssociationsToBeApprovedByUser(User user);

    public List<Land> getAllLandDefineAMAssociationsToBeApprovedByUser(User user);

    public List<LandDetails> getLandDefineAMAssociationsToBeApproved(int gnDivisionId, User user);

    public List<LandDetails> getLandToBeDefineAMAssociations(int gnDivisionId, User user);

    public List<LandAssociationDetails> getLandToBeAssociations(int gnDivisionId, User user);

    public List<LandDetails> getLandAssociations(int gnDivisionId, User user);

    /**
     * Search lands of the DSDivision by Land Name
     *
     * @param landName Name of the land to filter
     * @param dsId     id if land
     * @param user     User requesting to filter lands
     * @return List of lands match the filtering criteria.
     */
    public List<Land> searchActiveLandsOfDSDivisionByLandName(String landName, int dsId, User user);

    /**
     * Search lands of the DSDivision by Land Name
     *
     * @param landName Name of the land to filter
     * @param user     User requesting to filter lands
     * @return List of lands match the filtering criteria.
     */
    public List<Land> searchActiveLandsOfDSDivisionByLandName(String landName, User user);

    /**
     * Search lands of the DSDivision by Plan No
     *
     * @param planNo Plan Number to filter
     * @param user   User requesting to filter lands
     * @return List of lands match the filtering criteria
     */
    public List<Land> searchActiveLandsOfDSDivisionByPlanNo(String planNo, User user);

    /**
     * Search lands of the DSDivision by Lot No
     *
     * @param lotNo Lot Number to be filter
     * @param user  User requesting to filter lands
     * @return List of lands match the filtering criteria
     */
    public List<Land> searchActiveLandsOfDSDivisionByLotNo(String lotNo, User user);

    /**
     * Search lands of DSDivision by Holder Name
     *
     * @param holderName Name of the holder to filter
     * @param user       User requesting to filter lands
     * @return List of lands match the filtering criteria
     */
    public List<Land> searchActiveLandsOfDSDivisionByHolderName(String holderName, User user);

    /**
     * Search all active lands of given D.S. Division
     *
     * @param dsDivisionId Id of the D.S. Division
     * @return List of lands of the D.S. Division
     */
    public List<Land> searchAllActiveApprovedLandsOfDSDivision(int dsDivisionId);

    public List<Land> searchAllActiveApprovedLandsOfDistrict(int districtId);

    public List<Land> searchChildrenByParentLand(User user, long landId);

    public List<Land> searchAllChildrenByParentLand(User user, long landId);

    public List<Land> searchChildrenByParentReferenceNumber(User user, long landReferenceNumber);

    public List<Land> searchLandByPlanNo(User user, String planNo);

    public List<Land> searchLandByPlanNoAndLotNo(User user, String planNo, String lotNo);

    public List<LandDetails> getAllActivePendingIncompleteLands(User user, int pageNo, int noOfRows);

    public List<LandDetails> getAllActivePendingIncompleteLandsByGNDivision(User user, int gnDivisionId, int pageNo, int noOfRows);

    /**
     * Search all lands of the a given dsDivision in User's area by searchText, for users above ORDS
     *
     * @param landName,planNo,lotNo,holderName
     *                     search texts
     * @param dsDivisionId Id of ds division
     * @param pageNo       Used for pagination
     * @return List of lands match the filtering criteria.
     */
    public List<Land> searchAllLandsOfDSDivision(String landName, String planNo,
                                                 String lotNo, String holderName, int dsDivisionId, int pageNo);

    /**
     * Search all lands of the a given district in User's area by searchText, for users above ORDS
     *
     * @param landName,planNo,lotNo,holderName
     *                   search texts
     * @param districtId Id of district
     * @param pageNo     Used for pagination
     * @return List of lands match the filtering criteria.
     */
    public List<Land> searchAllLandsOfDistrict(String landName, String planNo,
                                               String lotNo, String holderName, int districtId, int pageNo);

    /**
     * Search all lands of the many DSDivision in User's area by searchText, for users above ORDS
     *
     * @param landName,planNo,lotNo,holderName
     *               search texts
     * @param user   User requesting to filter lands
     * @param pageNo Used for pagination
     * @return List of lands match the filtering criteria.
     */
    public List<Land> searchAllLandsOfManyDSDivisionsOfUpperLevel(String landName, String planNo,
                                                                  String lotNo, String holderName, User user, int pageNo);

    public List<Object[]> getLandStats(int id, String searchBy, Land.ApprovalState landState, Date fromDate, Date toDate, int language);

    /**
     * Search all lands of the DSDivision by searchText for ORDS and lower levels
     *
     * @param landName,planNo,lotNo,holderName
     *               search texts
     * @param user   User requesting to filter lands
     * @param pageNo Used for pagination
     * @return List of lands match the filtering criteria.
     */
    public List<Land> searchAllLandsOfDSDivisionBySearchText(String landName, String planNo, String lotNo,
                                                             String holderName, User user, int pageNo);

    /**
     * Update land approval note
     *
     * @param land Land object
     * @param user User requesting the update
     */
    public void updateLandApprovalNote(Land land, User user);

    /**
     * Get the lands in detail mode and not approved yet. Both alienated and unalienated
     * Used by ORIP for loading all unapproved detail/inital lands in given DSDivision
     *
     * @param user         User
     * @param dsDivisionId dsDivision of needed lands
     * @param pageNo       Used for pagination
     * @param noOfRows     Used for pagination
     * @return List all lands in given DsDivision
     */
    public List<LandDetails> getAllActivePendingIncompleteLandsByDsDivision(User user, int dsDivisionId, int pageNo, int noOfRows);

}
